// 实现异步工作器
#ifndef __M_LOOPER_H__
#define __M_LOOPER_H__

#include<thread>
#include<mutex>
#include"buffer.hpp"
#include<condition_variable> 
#include<functional>
#include<memory>
#include<atomic>

namespace log
{
    using Functor=std::function<void(Buffer &)>;
    enum class AsyncType
    {
        ASYNC_SAFE,
        ASYNC_UNSAFE
    };
    class AsyncLooper
    {
        public:
            using ptr=std::shared_ptr<AsyncLooper>;
            AsyncLooper(const Functor &cb,AsyncType loop_type=AsyncType::ASYNC_SAFE):_stop(false),
                _looper_type(loop_type),
                _thread(std::thread(&AsyncLooper::threadEntry,this)),
                _callback(cb)
            {}

            ~AsyncLooper()
            {
                stop();
            }

            void stop()
            {
                _stop=true;
                _cond_con.notify_all();//唤醒所有工作线程
                _thread.join();
            }

            void push(const char *data,size_t len)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                if(_looper_type==AsyncType::ASYNC_SAFE)
                    _cond_pro.wait(lock,[&](){return _pro_buf.writeAbleSize()>=len;});
                _pro_buf.push(data,len);
                _cond_con.notify_one();
            }
        private:
            void threadEntry()
            {
                while(1)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    _cond_con.wait(lock,[&](){return _stop|| !_pro_buf.empty();});
                    if(_stop&&_pro_buf.empty()) break;
                    _con_buf.swap(_pro_buf);
                    if(_looper_type==AsyncType::ASYNC_SAFE)
                        _cond_pro.notify_all();
                }
                _callback(_con_buf);
                _con_buf.reset();
            }    

        private:
            Functor _callback;//集体对缓冲区数据进行处理的回调函数
        private:
            AsyncType _looper_type;
            std::atomic<bool> _stop;
            Buffer _pro_buf;
            Buffer _con_buf;
            std::mutex  _mutex;
            std::condition_variable _cond_pro;
            std::condition_variable _cond_con;
            std::thread _thread;
    };
}

#endif